{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "2a8071da",
   "metadata": {},
   "source": [
    "Week 2, Day 4 - Use of Tools with openAI - Saurabh Gupta. For any feedback, please mail it to srbmisc@gmail.com, I would love connecting with you to discuss more on this, potentially improving it. Thank you for your read.\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "08f50ff5",
   "metadata": {},
   "source": [
    "# 🔍 LinkedIn Job Search Conversationally with OpenAI and JobSpy\n",
    "\n",
    "Looking for a job on LinkedIn but tired of manually scrolling through endless listings? This Python project simplifies your job hunt by automating the process of searching LinkedIn job postings based on your **desired role** and **location**.\n",
    "\n",
    "## 🚀 What It Does\n",
    "\n",
    "Using the powerful Python scraping library **`jobspy`** [Github Link](https://github.com/speedyapply/JobSpy), this tool fetches **real-time job listings from LinkedIn** tailored to your input. Just provide:\n",
    "\n",
    "\n",
    "- 🧑‍💻 **Job Title** (e.g., *Data Scientist*, *Frontend Developer*)\n",
    "- 📍 **Location** (e.g., *New York*, *Remote*, *Berlin*)\n",
    "\n",
    "…and the script will return up to **3 curated job listings** matching your criteria — complete with **direct links to the job posts** on LinkedIn.\n",
    "\n",
    "## ✅ Key Features\n",
    "\n",
    "- 🔎 Real-time LinkedIn job scraping  \n",
    "- ⚡ Fast and minimalistic – only the top 3 results  \n",
    "- 🔗 Includes clickable links to the job listings  \n",
    "- 💬 Simple CLI input — no setup hassles\n",
    "\n",
    "## 📌 Use Case\n",
    "\n",
    "Whether you're actively job hunting or just exploring opportunities in your field, this tool helps you **stay updated** with fresh job listings — without opening a browser.\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "af6d6650",
   "metadata": {},
   "outputs": [],
   "source": [
    "try:\n",
    "  from jobspy import scrape_jobs\n",
    "except:\n",
    "  %pip install -U python-jobspy\n",
    "  from jobspy import scrape_jobs"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "a08eb7af",
   "metadata": {},
   "outputs": [],
   "source": [
    "# imports\n",
    "\n",
    "import os\n",
    "import json\n",
    "from dotenv import load_dotenv\n",
    "from openai import OpenAI\n",
    "import gradio as gr\n",
    "import pandas as pd"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "11a280b1",
   "metadata": {},
   "outputs": [],
   "source": [
    "load_dotenv(override=True)\n",
    "\n",
    "openai_api_key = os.getenv('OPENAI_API_KEY')\n",
    "if openai_api_key:\n",
    "    print(f\"OpenAI API Key exists and begins {openai_api_key[:8]}\")\n",
    "else:\n",
    "    print(\"OpenAI API Key not set\")\n",
    "    \n",
    "MODEL = \"gpt-4.1-mini\"\n",
    "openai = OpenAI()\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "dbac4cb6",
   "metadata": {},
   "outputs": [],
   "source": [
    "def callExternalAPI(title, location) -> str:\n",
    "    jobs = pd.DataFrame(scrape_jobs(\n",
    "        site_name=[\"linkedin\"],\n",
    "        search_term=title,\n",
    "        location=location,\n",
    "        results_wanted=3,\n",
    "        hours_old=48\n",
    "    ))\n",
    "    print(f\"Found {len(jobs)} jobs\")\n",
    "    if len(jobs) > 0:\n",
    "        df = pd.DataFrame(jobs.loc[:,['title','company','location','date_posted','job_url']])\n",
    "        df = df.fillna('N/A')\n",
    "        return df.to_json()\n",
    "    return 'No results found'"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "b44a92f6",
   "metadata": {},
   "outputs": [],
   "source": [
    "system_message = ''' You are a helpful assistant for a Jobs Agency who helps users with job listings available.\n",
    "Give short, courteous answers to the users. Tell the user you can bring max 3 job listings at once. Present the job listings to the user in nice Markdown.\n",
    "Always be accurate. If you don't know the answer, say so.'''"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "339ac21b",
   "metadata": {},
   "outputs": [],
   "source": [
    "getData_function = {\n",
    "    \"name\": \"callExternalAPI\",\n",
    "    \"description\": '''Get the Job listings for the provided job title and/or location. Call this whenever the user needs specific job listings data for the title or location that they provide. Following are few examples - \n",
    "     1. Give me the jobs available for Software Engineer at Gurugram, India. - In such case, you can call this function by passing the job_title as Software Engineer and job_location as Gurugram, India.\n",
    "     2. Give me the jobs available for Software Engineer. - In such case, you can call this function by passing the job_title as Software Engineer and job_location as blank string.\n",
    "     3. Give me the jobs available at Gurugram, India. - In such case, you can call this function by passing the job_title as blank string and job_location as Gurugram, India.\n",
    "     ''',\n",
    "    \"parameters\": {\n",
    "        \"type\": \"object\",\n",
    "        \"properties\": {\n",
    "            \"job_title\": {\n",
    "                \"type\": \"string\",\n",
    "                \"description\": \"The title or position or designation of the job the user is interested in\",\n",
    "            },\n",
    "            \"job_location\": {\n",
    "                \"type\": \"string\",\n",
    "                \"description\": \"The location of the job the user is interested in\",\n",
    "            }\n",
    "        },\n",
    "        \"required\": [\"job_title\",\"job_location\"],\n",
    "        \"additionalProperties\": False\n",
    "    }\n",
    "}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "892250a4",
   "metadata": {},
   "outputs": [],
   "source": [
    "tools = [{\"type\": \"function\", \"function\": getData_function}]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "4be6fd80",
   "metadata": {},
   "outputs": [],
   "source": [
    "# We have to write that function handle_tool_call:\n",
    "\n",
    "def handle_tool_call(message):\n",
    "    tool_call = message.tool_calls[0]\n",
    "    arguments = json.loads(tool_call.function.arguments)\n",
    "    job_title = arguments.get('job_title')\n",
    "    job_location = arguments.get('job_location')\n",
    "    jobs = callExternalAPI(job_title,job_location)\n",
    "    response = {\n",
    "        \"role\": \"tool\",\n",
    "        \"content\": json.dumps({\"job_title\": job_title,\"job_location\": job_location,\"job_listings\": jobs}),\n",
    "        \"tool_call_id\": tool_call.id\n",
    "    }\n",
    "    return response"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "9d0b5b08",
   "metadata": {},
   "outputs": [],
   "source": [
    "def chat(message, history):\n",
    "    messages = [{\"role\": \"system\", \"content\": system_message}] + history + [{\"role\": \"user\", \"content\": message}]\n",
    "    response = openai.chat.completions.create(model=MODEL, messages=messages, tools=tools)\n",
    "\n",
    "    if response.choices[0].finish_reason==\"tool_calls\":\n",
    "        message = response.choices[0].message\n",
    "        response = handle_tool_call(message)\n",
    "        messages.append(message)\n",
    "        messages.append(response)\n",
    "        response = openai.chat.completions.create(model=MODEL, messages=messages)\n",
    "    \n",
    "    return response.choices[0].message.content"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "085b4aae",
   "metadata": {},
   "outputs": [],
   "source": [
    "gr.ChatInterface(fn=chat, type=\"messages\").launch()"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "venv",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.12.11"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
